package cn.tpshion.shop.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.tpshion.shop.common.BaseConstant;
import cn.tpshion.shop.common.BizException;
import cn.tpshion.shop.config.support.OneKeyProperties;
import cn.tpshion.shop.domain.dto.LoginDTO;
import cn.tpshion.shop.domain.dto.OneKeyLoginDTO;
import cn.tpshion.shop.domain.dto.RegisterDTO;
import cn.tpshion.shop.domain.entity.Task;
import cn.tpshion.shop.domain.entity.User;
import cn.tpshion.shop.domain.vo.LoginVO;
import cn.tpshion.shop.mapper.TaskMapper;
import cn.tpshion.shop.mapper.UserMapper;
import cn.tpshion.shop.service.AuthService;
import cn.tpshion.shop.util.AssertUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.dypnsapi20170525.Client;
import com.aliyun.dypnsapi20170525.models.GetMobileRequest;
import com.aliyun.dypnsapi20170525.models.GetMobileResponse;
import com.aliyun.dypnsapi20170525.models.GetMobileResponseBody;
import com.aliyun.teautil.models.RuntimeOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class AuthServiceImpl implements AuthService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private Client client;

    @Resource
    private OneKeyProperties oneKeyProperties;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private TaskMapper taskMapper;

    @Override
    public LoginVO login(LoginDTO dto) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone, dto.getPhone());
        User user = userMapper.selectOne(queryWrapper);
        AssertUtil.isTrue(!dto.getPassword().equals(user.getPassword()), "用户不存在或者密码不正确");
        return ofLoginResult(user);
    }

    @Override
    public LoginVO oneKeyLogin(OneKeyLoginDTO dto) {
        GetMobileRequest request = new GetMobileRequest();
        request.setAccessToken(dto.getToken());

        RuntimeOptions runtime = new RuntimeOptions();

        try {
            GetMobileResponse mobileWithOptions = client.getMobileWithOptions(request, runtime);
            log.info("mobileWithOptions:{}", JSON.toJSONString(mobileWithOptions));

            AssertUtil.isTrue(mobileWithOptions.getStatusCode() != 200, "登录接口异常");

            GetMobileResponseBody body = mobileWithOptions.getBody();
            AssertUtil.isFalse("OK".equals(body.getCode()), body.getMessage());

            String mobile = body.getGetMobileResultDTO().getMobile();
            AssertUtil.isBlank(mobile, "获取手机号码失败");

            // 查询该用户是否存在
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone, mobile);
            User user = userMapper.selectOne(queryWrapper);

            if (Objects.isNull(user)) {
                User userSave = new User();
                userSave.setPhone(mobile);
                userMapper.insert(userSave);
                user = userMapper.selectOne(queryWrapper);

                successTask(user.getId(), "register");
            }

            return ofLoginResult(user);
        } catch (Exception e) {
            throw new BizException("登录失败");
        }
    }

    @Override
    public LoginVO register(RegisterDTO dto) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone, dto.getPhone());
        AssertUtil.isTrue(userMapper.exists(queryWrapper), "用户已存在，请勿重复注册");

        User user = new User();
        user.setPhone(dto.getPhone());
        user.setPassword(dto.getPassword());

        userMapper.insert(user);

        successTask(user.getId(), "register");
        return ofLoginResult(user);
    }

    @Override
    public String authKey() {
        return oneKeyProperties.getAuthKey();
    }

    @Override
    public void logout() {
        Object loginId = StpUtil.getLoginId();
        StpUtil.logout(loginId);
    }

    private LoginVO ofLoginResult(User user) {
        StpUtil.login(user.getId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        LoginVO result = new LoginVO();
        result.setPhone(user.getPhone());
        result.setToken(tokenInfo.getTokenValue());
        return result;
    }

    private void successTask(Long uid, String type) {
        try {
            // 查询任务
            Task task = getTask(type);
            AssertUtil.isNull(task, "任务不存在");

            HashOperations<String, String, String> hash = redisTemplate.opsForHash();
            if ("register".equals(task.getType())) {
                hash.putIfAbsent(BaseConstant.TASK_REGISTER_KEY, String.valueOf(uid), "0");
            } else {
                String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                String key = BaseConstant.TASK_KEY + date;
                String userKey = task.getType() + "-" + uid;
                hash.putIfAbsent(key, userKey, "0");

                Long expire = redisTemplate.getExpire(key);
                if (expire <= 0) {
                    redisTemplate.expire(key, 2, TimeUnit.DAYS);
                }
            }
        } catch (Exception e) {
            log.error("successTask error:{}", e.getMessage(), e);
        }
    }

    private Task getTask(String type) {
        LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Task::getType, type);
        return taskMapper.selectOne(queryWrapper);
    }
}
